package com.netx.generics.util;
import com.netx.generics.translation.TranslationStep;
import com.netx.generics.translation.Results;
import com.netx.generics.translation.Token;
import java.util.List;


public class BuiltinParser extends TranslationStep {

	private int _current;
	private List<? extends Token> _tokens;

	public BuiltinParser(BuiltinScanner scanner) {
		super(scanner);
		_current = 0;
		_tokens = null;
	}

	@SuppressWarnings("unchecked")
	public Object performWork(Results r) {
		_current = 0;
		_tokens = (List<? extends Token>)r.getContents();
		try {
			SymbolExpression expr = new SymbolExpression();
			while(_current < _tokens.size()) {
				if(_tokens.get(_current).getType() == BuiltinToken.FUNCTION) {
					expr.contents.add(_parseExpression(r));
				}
				else if(_tokens.get(_current).getType() == BuiltinToken.TEXT) {
					expr.contents.add(new SymbolText(_tokens.get(_current++)));
				}
				else {
					// Consider everything else as TEXT:
					expr.contents.add(new SymbolText(_tokens.get(_current++)));
				}
			}
			return expr;
		}
		catch(IndexOutOfBoundsException ioobe) {
			r.addError("unexpected end of expression", _tokens.get(_current-1));
			return null;
		}
	}

	private BuiltinSymbol _parseExpression(Results r) {
		// Function call:
		if(_tokens.get(_current).getType() == BuiltinToken.FUNCTION) {
			SymbolFunction sf = new SymbolFunction(_tokens.get(_current++));
			if(!_tokens.get(_current).toString().equals("(")) {
				addError(r, "expected '('");
			}
			else {
				_current++;
			}
			if(_tokens.get(_current).toString().equals(")")) {
				_current++;
				return sf;
			}
			else {
				// parse function arguments:
				while(true) {
					sf.arguments.add(_parseExpression(r));
					if(_tokens.get(_current).toString().equals(",")) {
						_current++;
					}
					else {
						break;
					}
				}
				if(!_tokens.get(_current).toString().equals(")")) {
					addError(r, "expected ')'");
				}
				else {
					_current++;
				}
				return sf;
			}
		}
		// Sum:
		else if(_tokens.get(_current).getType() == Token.STRING_CONSTANT || _tokens.get(_current).getType() == Token.INTEGER_CONSTANT || _tokens.get(_current).getType() == Token.FLOAT_CONSTANT) {
			SymbolConstant st = new SymbolConstant(_tokens.get(_current++));
			if(_tokens.size() == _current) {
				return st;
			}
			else if(_tokens.get(_current).getType() == Token.OPERATOR) {
				SymbolSum sum = new SymbolSum();
				sum.operands.add(st);
				while(_tokens.get(_current).getType() == Token.OPERATOR) {
					_current++;
					sum.operands.add(_parseExpression(r));
				}
				return sum;
			}
			else {
				return st;
			}
		}
		else {
			addError(r, "unexpected token");
			return null;
		}
	}
	
	protected void addError(Results r, String msg) {
		Token token = _tokens.get(_current);
		r.addError(msg+": '"+token.getValue()+"'", token);
	}
}
